/*
 *	ME2 C++ SDK
 *	Copyright (c) 2010 _silencer
 *
 *	Permission is hereby granted, free of charge, to any person
 *	obtaining a copy of this software and associated documentation
 *	files (the "Software"), to deal in the Software without
 *	restriction, including without limitation the rights to use,
 *	copy, modify, merge, publish, distribute, sublicense, and/or sell
 *	copies of the Software, and to permit persons to whom the
 *	Software is furnished to do so, subject to the following
 *	conditions:
 *
 *	The above copyright notice and this permission notice shall be
 *	included in all copies or substantial portions of the Software.
 *
 *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *	OTHER DEALINGS IN THE SOFTWARE.
 */

#include "stdafx.h"
#include "unreal_object.h"
#include "unreal_function.h"
#include "unreal_class.h"

namespace unreal
{
	uclass* get_package_class( char* class_name, char* package_name )
	{
		for ( unsigned int i( 0 ); i < uobject::table_->size(); i++ )
		{
			uobject* obj( (*uobject::table_)[i] );

			if ( obj->is_valid() )
			{
				uobject* obj_outer( obj->get_outer() );
				uclass* obj_class( obj->get_class() );

				if ( !obj_outer->is_valid() || !obj_class->is_valid() )
					continue;

				if ( boost::iequals( class_name, obj->get_name() ) )
				{
					if ( boost::iequals( package_name, obj_outer->get_name() ) )
					{
						if ( boost::iequals( "Class", obj_class->get_name() ) )
						{
							return reinterpret_cast<uclass*>(obj);
						}
					}
				}
			}
		}

		return 0;
	}

	uarray<uobject*>* uobject::table_ = reinterpret_cast<uarray<uobject*>*>(OFFSET_UOBJECT_TABLE);
	process_event_type uobject::process_event_ = reinterpret_cast<process_event_type>(OFFSET_UOBJECT_PROCESSEVENT);

	void uobject::call_function( ufunction* function, void* parms, void* result )
	{
		if ( function->is_valid() )
		{
			/*	
				Fool the engine in processing native functions,
				else we would have to reverse engineer the stack class and functions to be able to call them.
			 */
			uint32 flags( function->get_function_flags() );
			uint16 index( function->get_native_index() );

			function->set_function_flags( flags ^ ufunction_native );
			function->set_native_index( 0 );

			process_event_( this, function, parms, result );

			function->set_function_flags( flags );
			function->set_native_index( index );
		}
	}

	std::string uobject::get_path_name( const uobject* last_outer ) const
	{
		std::string result;

		if ( this != last_outer )
		{
			if ( outer_ != last_outer )
				result += outer_->get_path_name( last_outer ) + ".";

			result += get_name();
		}
		else
		{
			result = "None";
		}

		return result;
	}

	std::string uobject::get_full_name() const
	{
		if( this )
			return std::string( get_class()->get_name() ) + " " + get_path_name( 0 );
		else
			return "None";
	}

	bool uobject::is_a( uclass* base ) const
	{
		for( uclass* item( class_ ); item; item = reinterpret_cast<uclass*>(item->get_super_field()) )
		{
			if( item == base )
				return true;
		}

		return base == 0;
	}

	bool uobject::is_in( uobject* outer ) const
	{
		for( uobject* item( outer_ ); item; item = item->outer_ )
		{
			if( item == outer )
				return true;
		}

		return outer == 0;
	}

	uobject* uobject::get_upper_outer() const
	{
		uobject* item( outer_ );

		while ( item->outer_ )
		{
			item = item->outer_;
		}

		return item;
	}
}
